#pragma once
#include <iostream>
#include <pthread.h>
#include <queue>
using namespace std;

const int defaultcapacity = 10;

template <class T> 
class blockqueue {
    public :
    blockqueue(const int capacity = defaultcapacity) 
        :_capacity(capacity)
    {
        // 初始化锁和条件变量
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
    }

    bool IsFull() {
        return _bq.size() == _capacity;
    }

    bool IsEmpty(){
        return _bq.empty();
    }
    
    void Push(const T& in) {
        // 生产者生产资源
        // 先加锁
        pthread_mutex_lock(&_mutex);
        while (IsFull()) { // 这里使用while来判断的原因是为了防止“伪唤醒"
            pthread_cond_wait(&_p_cond, &_mutex);
        }
        _bq.push(in);
        pthread_cond_signal(&_c_cond); // 唤醒消费者，让消费者来消费
        pthread_mutex_unlock(&_mutex);
    }

    void Pop(T* out) {
        // 先加锁
        pthread_mutex_lock(&_mutex);
        while (IsEmpty()) {
            pthread_cond_wait(&_c_cond, &_mutex);
        }
        // cout << "_bq.size() == " << _bq.size() << endl;
        *out = _bq.front();
        _bq.pop();

        pthread_cond_signal(&_p_cond); // 唤醒生产者，让生产者生产
        pthread_mutex_unlock(&_mutex);

    }



    ~blockqueue() {
        // 销毁锁和条件变量
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }



    private :
    queue<T> _bq;
    int _capacity;
    pthread_mutex_t _mutex; // 控制生产者消费者互斥的锁
    pthread_cond_t _c_cond; // 消费者条件变量
    pthread_cond_t _p_cond; // 生产者条件变量
};